package com.xinxin.socket.context;

import com.google.common.collect.Maps;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ChannelContext {

    private static final int EXPIRE_DELAY = 15 * 60 * 1000;

    private static final ChannelContext INSTANCE = new ChannelContext();

    private final ConcurrentMap<Channel, ScheduledFuture> activeChannel = Maps.newConcurrentMap();

    private ChannelContext() {
        new Timer().schedule(new TimerTask() {

            @Override
            public void run() {
                log.info("Check long link alive per 15 minutes.");
                for (Channel ch : activeChannel.keySet()) {
                    if (activeChannel.get(ch).isSuccess()) {
                        ch.close();
                    }
                }
            }
        }, EXPIRE_DELAY, EXPIRE_DELAY);
    }

    public static ChannelContext getInstance() {
        return INSTANCE;
    }

    private ScheduledFuture scheduleCheckChannel(ChannelHandlerContext ctx) {
        return ctx.executor().schedule(() -> {
            log.info("Channel expired: {}", ctx.channel().toString());
            ctx.channel().close();
        }, EXPIRE_DELAY, TimeUnit.MILLISECONDS);
    }

    public void channelActive(ChannelHandlerContext ctx) {
        activeChannel.put(ctx.channel(), scheduleCheckChannel(ctx));
    }

    public void receiveHeart(ChannelHandlerContext ctx) {
        Objects.requireNonNull(activeChannel.put(ctx.channel(), scheduleCheckChannel(ctx))).cancel(true);
    }

    public void channelInactive(ChannelHandlerContext ctx) {
        activeChannel.remove(ctx.channel()).cancel(true);
    }
}
